import { githubRepositories } from "@/utils/api";
import React from "react";
import InfiniteScroll from "react-infinite-scroller";
import { Grid, Row, Col } from "react-flexbox-grid";
import { Repository } from "./Repository";
import { Skeleton } from "./Skeleton";
import { Tabs } from "./Tabs";
import styles from "./Popular.less";
import { Loading } from "./Loading";
import { Error } from "./Error";

function getCacheVal(cache, key) {
  const item = cache[key];
  if (!item) return null;
  if (item.timeout < Date.now()) return null;
  return item.val;
}
function buildCache(val, timeoutSec) {
  return {
    timeout: Date.now() + timeoutSec * 1000,
    val,
  };
}
const skeletonData = [];
function getSkeletonData(size) {
  if (skeletonData.length === size) {
    return skeletonData;
  }
  skeletonData.length = 0;
  for (let i = 0; i < size; i += 1) {
    skeletonData.push({ id: -1 });
  }
  return skeletonData;
}

export class Popular extends React.Component {
  constructor(prop) {
    super(prop);
    this.onRouteUrlQuery = prop.onRouteUrlQuery;
    this.state = {
      currTabVal: prop.query?.lang || "All",
      tabList: [
        { val: "All", text: "All" },
        { val: "javascript", text: "Javascript" },
        { val: "ruby", text: "Ruby" },
        { val: "java", text: "Java" },
        { val: "css", text: "CSS" },
      ],
      reps: [],
      pageNum: 1,
      pageCount: 0,
      loadTab: null,
      firstPageCache: {},
    };
  }

  async componentDidMount() {
    await this.changeTab(this.state.currTabVal);
  }

  onTabClick = async (lang) => {
    this.onRouteUrlQuery({ lang });
    await this.changeTab(lang);
  };

  onScrollLoad = async () => {
    await this.loadList(this.state.currTabVal, this.state.pageNum + 1);
  };

  async changeTab(tabVal) {
    const currTab = this.state.tabList.find((t) => t.val === tabVal);
    if (!currTab) return;

    await this.loadList(tabVal, 1);
  }

  async loadList(tabVal, pageNum) {
    let q = "stars:>1";
    if (tabVal !== "All") {
      q += ` language:${tabVal}`;
    }
    const pageSize = 10;

    if (pageNum === 1) {
      // 如果加载的是首页,尝试先从时效首屏缓存中获取
      const cacheData = getCacheVal(this.state.firstPageCache, tabVal);
      if (cacheData) {
        return this.setState({
          loadTab: null,
          currTabVal: tabVal,
          reps: cacheData.items,
          pageNum,
          pageCount: parseInt(
            (cacheData.total_count + pageSize - 1) / pageSize,
            10
          ),
        });
      }
    }

    this.setState(() => {
      const newState = {
        loadTab: tabVal,
        errorMsg: null,
      };
      if (pageNum === 1) {
        newState.reps = getSkeletonData(pageSize);
      }
      return newState;
    });
    const res = await githubRepositories(q, pageSize, pageNum);
    if (res.code !== 200) {
      this.setState({
        loadTab: null,
        currTabVal: tabVal,
        errorMsg: `加载错误:[${res.code}] ${res.desc}`,
      });
      return false;
    }
    // 加载回来再切换到标签
    this.setState((state) => {
      const firstPageCache =
        pageNum === 1
          ? {
              ...state.firstPageCache,
              [tabVal]: buildCache(res.data, 10),
            }
          : state.firstPageCache;
      return {
        loadTab: null,
        currTabVal: tabVal,
        reps:
          pageNum === 1 ? res.data.items : [...state.reps, ...res.data.items],
        pageNum,
        pageCount: parseInt(
          (res.data.total_count + pageSize - 1) / pageSize,
          10
        ),
        firstPageCache,
      };
    });
    return true;
  }

  render() {
    const { loadTab, errorMsg, currTabVal, tabList, reps } = this.state;
    const loading = !!loadTab;
    const hasMore = this.state.pageNum < this.state.pageCount;
    const repsEl = reps.map((r, index) => (
      <Col key={index} sm={6} md={4} lg={3}>
        {r.id === -1 ? (
          <Skeleton rank={index + 1} />
        ) : (
          <Repository repository={r} rank={index + 1} />
        )}
      </Col>
    ));
    return (
      <div>
        <Tabs
          onTabClick={this.onTabClick}
          currentVal={currTabVal}
          list={tabList}
          loadTab={loadTab}
          className={styles.tab}
        />
        {!!errorMsg && <Error errorMsg={errorMsg} />}
        <InfiniteScroll
          initialLoad={false}
          loadMore={this.onScrollLoad}
          hasMore={!loading && hasMore}
          loader={null}
        >
          <Grid fluid>
            <Row style={{ justifyContent: "space-around" }}>{repsEl}</Row>
          </Grid>
        </InfiniteScroll>
        <div className={styles.blank}>
          {!!errorMsg && <Error errorMsg={errorMsg} />}
          {loading && <Loading />}
        </div>
      </div>
    );
  }
}
export default Popular;
